package com.alone.jpa.entity.enhancer;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.StrUtil;
import com.alone.jpa.entity.annotation.AutoFill;
import com.alone.jpa.entity.annotation.Enhanced;
import com.alone.jpa.entity.annotation.FillTiming;
import com.alone.jpa.entity.support.EntityFieldsCache;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.util.ClassUtils;

import java.lang.reflect.Field;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;

/**
 * 字段填充处理器
 *
 * @author Alone
 */
@RequiredArgsConstructor
public class AutoFillHandler implements EntityEnhanceHandler {

    private final AutoFillDefaultValueProvider defaultValueProvider;

    @Override
    public void prePersist(Object entity) {
        Class<?> clazz = entity.getClass();
        if (notNeedHandle(clazz)) {
            return;
        }
        List<Field> fields = EntityFieldsCache.getFields(clazz);
        for (Field field : fields) {
            AutoFill autoFill = field.getAnnotation(AutoFill.class);
            boolean needHandle = autoFill != null
                    && (autoFill.timing().equals(FillTiming.INSERT)
                    || autoFill.timing().equals(FillTiming.INSERT_UPDATE));
            if (needHandle) {
                handleFill(entity, field, autoFill.column(), autoFill.isCover());
            }
        }
    }

    @Override
    public void preUpdate(Object entity) {
        Class<?> clazz = entity.getClass();
        if (notNeedHandle(clazz)) {
            return;
        }
        List<Field> fields = EntityFieldsCache.getFields(clazz);
        for (Field field : fields) {
            AutoFill autoFill = field.getAnnotation(AutoFill.class);
            boolean needHandle = autoFill != null
                    && (autoFill.timing().equals(FillTiming.UPDATE)
                    || autoFill.timing().equals(FillTiming.INSERT_UPDATE));
            if (needHandle) {
                handleFill(entity, field, autoFill.column(), autoFill.isCover());
            }
        }
    }


    private boolean notNeedHandle(Class<?> clazz) {
        Enhanced enhanced = clazz.getDeclaredAnnotation(Enhanced.class);
        return enhanced != null && !enhanced.isAutoFill();
    }

    /**
     * @param entity 目标对象
     * @param field  属性
     */
    @SneakyThrows
    private void handleFill(Object entity, Field field, String custColumn, boolean isCover) {
        Map<String, Supplier<Object>> valueMap = defaultValueProvider.getValueMap();
        Supplier<Object> valueSupplier = valueMap.get(CharSequenceUtil.isNotBlank(custColumn) ? custColumn : field.getName());
        // 如果填充值为空
        if (valueSupplier == null) {
            return;
        }
        // 如果用户有手动设置的值
        Object userValue = field.get(entity);
        String setValueStr = StrUtil.str(userValue, Charset.defaultCharset());
        if (StrUtil.isNotBlank(setValueStr) && !isCover) {
            return;
        }
        // field 类型相同时设置
        Class<?> fieldType = field.getType();
        Object fieldValue = valueSupplier.get();
        if (ClassUtils.isAssignableValue(fieldType, fieldValue)) {
            field.set(entity, fieldValue);
        }
    }
}
